#!/usr/bin/env python3
r"""
This is an extended user library to support Robot Selenium code.
The class contains functions which the robot framework will use
and import as a user-defined keyword.
"""
import json
import ssl

import gen_print as gp  # NOQA
import gen_valid as gv  # NOQA
import requests
import websocket


class event_notification:  # NOQA
    r"""
    Main class to subscribe and receive event notifications.
    """

    def __init__(self, host, username, password):
        r"""
        Initialize instance variables.

        Description of argument(s):
        host        The IP or host name of the system to subscribe to.
        username    The username for the host system.
        password    The password for the host system.
        """
        self.__host = host
        self.__user = username
        self.__password = password
        self.__websocket = None

    def __del__(self):
        try:
            self.__websocket.close()
        except AttributeError:
            pass

    def login(self):
        r"""
        Login and return session object.
        """
        http_header = {"Content-Type": "application/json"}
        session = requests.session()
        response = session.post(
            "https://" + self.__host + "/login",
            headers=http_header,
            json={"data": [self.__user, self.__password]},
            verify=False,
            timeout=30,
        )
        gv.valid_value(response.status_code, valid_values=[200])
        login_response = json.loads(response.text)
        gp.qprint_var(login_response)
        gv.valid_value(login_response["status"], valid_values=["ok"])
        return session

    def subscribe(self, dbus_path, enable_trace=False):
        r"""
        Subscribe to the given path and return a list of event notifications.

        For more details on "subscribe" and "events" go to
        https://github.com/openbmc/docs/blob/master/rest-api.md#event-subscription-protocol

        Example robot code:
        ${event_notifications}=  Subscribe  /xyz/openbmc_project/sensors
        Rprint Vars  event_notifications

        Example output:
        event_notifications:
          [0]:
            [interface]:             xyz.openbmc_project.Sensor.Value
            [path]:                  /xyz/openbmc_project/sensors/temperature/ambient
            [event]:                 PropertiesChanged
            [properties]:
              [Value]:               23813

        Description of argument(s):
        dbus_path              The subscribing event's path (e.g.
                               "/xyz/openbmc_project/sensors").
        enable_trace           Enable or disable trace.
        """

        session = self.login()
        cookies = session.cookies.get_dict()
        # Convert from dictionary to a string of the following format:
        # key=value;key=value...
        cookies = gp.sprint_var(
            cookies,
            fmt=gp.no_header() | gp.strip_brackets(),
            col1_width=0,
            trailing_char="",
            delim="=",
        ).replace("\n", ";")

        websocket.enableTrace(enable_trace)
        self.__websocket = websocket.create_connection(
            f"wss://{self.__host}/subscribe",
            sslopt={"cert_reqs": ssl.CERT_NONE},
            cookie=cookies,
        )
        dbus_path = [path.strip() for path in dbus_path.split(",")]
        dbus_path = {"paths": dbus_path}

        self.__websocket.send(json.dumps(dbus_path))
        event_notifications = json.loads(self.__websocket.recv())
        self.__websocket.close()
        return event_notifications
